# 从news/__init__文件中导入蓝图对象
from . import news_blue
# 导入flask内置的模块
from flask import Flask, session, render_template,current_app,jsonify,request,g
#　传入模型类
from info.models import User,Category, News,Comment
#
from info.utils.response_code import RET
#　导入常量文件
from info import constants,db
# 导入登录验证装饰器
from info.utils.commons import login_required

@news_blue.route('/')
@login_required
def index():
    # # 状态保持
    # session['itcast'] = '2018'
    '''
    项目首页数据加载
        一.检查用户的登陆状态：
        1.如果用户登陆了，显示用户名信息，否则提供登陆注册入口
        2.使用session对象，从redis中获取user_id
        3.根据user_id,查询mysql,获取用户信息
        4.传给模板
        二.新闻分类数据加载
        1.查询mysql，获取新闻分类数据
        三.点击排行
        1.查询mysql，获取新闻点击排行(按点击量排行，显示六条)

    :return:
    '''
    # # 使用请求上下文对象，获取user_id
    # user_id = session.get('user_id')
    # # 查询mysql,获取用户信息
    # user = None
    # try:
    #     user = User.query.get(user_id)
    # except Exception as e:
    #     current_app.logger.error(e)
    user = g.user

    # 新闻分类数据加载
    try:
        categories = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻分类数据失败')

    # 判断查询结果
    if not categories:
        return jsonify(errno=RET.NODATA,errmsg='无新闻分类数据')

    # 定义列表，用来存储便利后的新闻分类数据
    category_list = []
    # 遍历查询结果，调用模型类中to_dict函数，获取数据
    for category in categories:
        category_list.append(category.to_dict())

    # 查询新闻点击排行
    try:
        news_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻点击排行数据失败')

    # 判断查询结果
    if not news_list:
        return jsonify(errno=RET.NODATA,errmsg='无新闻点击排行数据')
    # 定义列表，存储查询结果
    news_click_list = []
    for news in news_list:
        news_click_list.append(news.to_dict())

    # 定义字典，用来存储返回给模板的数据
    # User中存入的数据不能直接通过属性查，
    # 需要通过实例化对象user调用to_dict方法
    data = {
        'user_info':user.to_dict() if user else None,
        'category_list':category_list,
        'news_click_list':news_click_list
    }

    return render_template('news/index.html', data=data)


@news_blue.route('/news_list')
def get_news_list():
    '''
    首页新闻列表
    1.获取参数，ajax发送get请求cid，page，per_page
    2.检查参数，把cid，page，per_page转成int类型
    3.判断分类id
    如果是最新分类：查询所有新闻
    paginate = News.query.filter().order_by(News.create_time.desc()).paginate(1,per_page,False)
    如果不是最新分类,根据分类查询新闻
    paginate = News.query.filter(News.category_id == cid).order_by(News.create_time.desc()).paginate(1,per_page,False)
    4.获取分页后的新闻列表，总页数，当前页数
    5.定义容器，遍历新闻列表
    6.返回数据（总页数，当前页数，新闻列表）

    :return:
    '''

    # 获取参数，如果没有就添加默认值
    cid = request.args.get('cid','1')
    page = request.args.get('page','1')
    per_page = request.args.get('per_page','10')

    # 转换数据类型
    try:
        cid,page,per_page = int(cid),int(page),int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR,errmsg='参数格式错误')

    # 判断新闻分类,如果不是最新，添加到过滤条件的列表中
    filters = []

    # #  查询新闻分类数据并分页
    # filters = [News.status == 0]
    # # 如果分类id不等于0,那么添加分类id的过滤
    # if cid != "0":
    #     filters.append(News.category_id == cid)
    if cid > 1:
        filters.append(News.category_id == cid)
    # 根据filters过滤条件查询mysql
    try:
        # paginate = News.query.filter(News.category_id == cid).order_by(News.create_time.desc()).paginate(page,per_page,False)
        # *filters相当于python语法中的拆包
        paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page,per_page,False)
        # if cid == 1:
        #     paginate = News.query.filter().order_by(News.create_time.desc()).paginate(1, per_page, False)
        # else:
        #     paginate = News.query.filter(News.category_id == cid).order_by(News.create_time.desc()).paginate(1,per_page,False)

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻列表数据失败')

    # 获取分页后的数据
    news_list = paginate.items # 新闻数据
    current_page = paginate.page # 当前页数
    total_page = paginate.pages # 总页数
    # 定义容器，存储分页的新闻列表数据
    news_dict_list = []
    for news in news_list:
        news_dict_list.append(news.to_dict())

    # 定义字典
    data = {
        'news_dict_list':news_dict_list,
        'current_page':current_page,
        'total_page':total_page
    }

    # 返回结果
    return jsonify(errno=RET.OK,errmsg='OK', data=data)

@news_blue.route('/<int:news_id>')
@login_required
def get_news_detail(news_id):
    '''
    新闻详情

    :param news_id:
    :return:
    '''
    # # 使用请求上下文对象，获取user_id
    # user_id = session.get('user_id')
    # # 查询mysql,获取用户信息
    # user = None
    # try:
    #     user = User.query.get(user_id)
    # except Exception as e:
    #     current_app.logger.error(e)
    user = g.user
    # 查询新闻点击排行
    try:
        news_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询新闻点击排行数据失败')

    # 判断查询结果
    if not news_list:
        return jsonify(errno=RET.NODATA, errmsg='无新闻点击排行数据')
    # 定义列表，存储查询结果
    news_click_list = []
    for news in news_list:
        news_click_list.append(news.to_dict())

    # 根据分类id查询具体的新闻
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻详情数据是白')

    # 判断查询结果
    if not news:
        return jsonify(errno=RET.NODATA,errmsg='无新闻详情数据')

    # 新闻带你及次数加1
    news.clicks += 1
    # 提交数据
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存数据失败')

    # 获取当前新闻的评论
    comments = []
    try:
        comments = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
    comment_list = []
    for comment in comments:
        comment_dict = comment.to_dict()
        comment_list.append(comment_dict)
    # 当前登录用户是否关注当前新闻作者
    is_followed = False
    # 判断用户是否收藏过该新闻
    is_collected = False
    if g.user:
        if news in g.user.collection_news:
            is_collected = True
        if news.user.followers.filter(User.id == g.user.id).count() > 0:
            is_followed = True


    data = {
        'user':user,
        'user_info': user.to_dict() if user else None,
        'news_detail':news.to_dict(),
        'news_click_list': news_click_list,
        'is_collected':is_collected,
        'comments':comment_list,
        "is_followed": is_followed,
    }

    # 渲染模板
    return render_template('news/detail.html',data=data)

@news_blue.route('/news_collect',methods=['POST'])
@login_required
def news_collection():
    '''
    用户收藏或取消收藏
    1.判断用户是否登录
    2.获取参数，news_id,action['cancel_collect','collect']
    3.检查参数，news_id转成int类型
    4.判断action在参数范围内
    5.查询数据库，确认新闻存在
    6.判断用户选择的是收藏还是取消收藏
    7.返回结果

    :return:
    '''

    user = g.user
    # 判断用户是否登录
    if not user:
        return jsonify(errno=RET.SESSIONERR,errmsg='用户未登录')

    # 获取参数
    news_id = request.json.get('news_id')
    action = request.json.get('action')

    # 检查参数
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数确实')
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR,errmsg='参数类型错误')

    # 检查action必须在范围内
    if action not in ['collect', 'cancel_collect']:
        return jsonify(errno=RET.PARAMERR,errmsg='参数范围错误')

    # 查询新闻
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻失败')

    # 判断查询结果
    if not news:
        return jsonify(errno=RET.NODATA,errmsg='无新闻数据')

    # 判断是否已收藏
    if action == 'collect':
        # 判断用户是否收藏过
        if news not in user.collection_news:
            user.collection_news.append(news)
    else:
        user.collection_news.remove(news)

    # 提交数据到数据库
    try:

        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存失败')
    return jsonify(errno=RET.OK,errmsg='成功')


# 评论新闻
@news_blue.route('/news_comment',methods=['POST'])
@login_required
def add_news_comment():
    '''

    添加评论
    :return:
    '''
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR,errmsg='未登录')

    #　获取参数
    news_id = request.json.get('news_id')
    content = request.json.get('comment')
    parent_id = request.json.get('parent_id')
    print(news_id,content)
    if not all([news_id, content]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数错误')

    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg='查询新闻数据失败')

    if not news:
        return jsonify(errno=RET.NODATA,errmsg='该新闻不存在')

    # 初始化模型，保存数据
    comment = Comment()
    comment.user_id = user.id
    comment.news_id = news_id
    comment.content = content
    if parent_id:
        comment.parent_id = parent_id

    # 保存到数据库中
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存评论失败')

    # 返回响应
    return jsonify(errno=RET.OK,errmsg='OK',data=comment.to_dict())



# 加载项目logo图标，favicon.ico
# 浏览器会默认请求项目根路径下的favicon文件
# http://127.0.0.1:5000/favicon.ico
@news_blue.route('/favicon.ico')
def favicon():
    # 发送文件给浏览器
    # send_static_file 是Falsk内置的一个访问静态路由的方法
    return current_app.send_static_file('news/favicon.ico')
